package com.fyl.custom_spring.context.support;

import com.fyl.custom_spring.beans.BeanDefinition;
import com.fyl.custom_spring.beans.MutablePropertyValues;
import com.fyl.custom_spring.beans.PropertyValue;
import com.fyl.custom_spring.beans.factory.support.BeanDefinitionReader;
import com.fyl.custom_spring.beans.factory.support.BeanDefinitionRegistry;
import com.fyl.custom_spring.beans.factory.xml.XmlBeanDefinitionReader;
import com.fyl.custom_spring.utils.StringUtils;
import org.dom4j.DocumentException;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * ioc容器的具体子实现类 用于加载类路径下的xml格式的配置文件
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{
    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        //快速构建解析器对象
        beanDefinitionReader= new XmlBeanDefinitionReader();
        try {
            this.refresh();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public Object getBean(String name) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        //判断对象容器中是否包含该名称的bean对象，如果包含直接返回，如果不包含直接创建
        Object obj = singletonObjects.get(name);
        if(null!=obj){
            return obj;
        }

        //获取beanDefinition对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        //读取bean信息中的className
        String className = beanDefinition.getClassName();
        //通过反射创建对象
        Class<?> clazz = Class.forName(className);
        Object beanObj = clazz.newInstance();

        //进行依赖注入操作
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
            //获取属性值
            String propertyName = propertyValue.getName();
            String value = propertyValue.getValue();
            String ref = propertyValue.getRef();
            if(null!=ref && !"".equals(ref)){
                //获取依赖的bean对象
                Object bean = getBean(ref);
                //获取方法名
                String methodName = StringUtils.getSetterMethodFieldName(propertyName);
                //获取所有的方法对象
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if(methodName.equals(method.getName())){
                        //执行方法
                        method.invoke(beanObj,bean);
                    }
                }
            }

            if(null!=value && !"".equals(value)){
                String methodName = StringUtils.getSetterMethodFieldName(propertyName);
                //获取method对象
                Method method = clazz.getMethod(methodName,String.class);
//                Method method = clazz.getMethod(methodName);
                method.invoke(beanObj,value);
            }
        }

        //返回beanObj之前，将该对象存储到map容器中
        singletonObjects.put(name, beanObj);
        return beanObj;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        Object bean = getBean(name);
        if (null==bean){
            return null;
        }
        return clazz.cast(bean);
    }

}
